﻿#region copyright
//<copyright>
// Copyright(C) 2012 TrackerRealm Corporation
// This file is part of the open source project - Jazz. http://jazz.codeplex.com
// 
// Jazz is open software: you can redistribute it and/or modify it 
// under the terms of the GNU Affero General Public License (AGPL) as published by 
// the Free Software Foundation, version 3 of the License.
// 
// Jazz is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty 
// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
//  See the GNU Affero General Public License (AGPL) for more details.
// 
// You should have received a copy of the GNU General Public 
// License along with Jazz.  If not, see <http://www.gnu.org/licenses/>.
//
// REMOVAL OF THIS NOTICE IS VIOLATION OF THE COPYRIGHT. 
//</copyright>
#endregion
using System;
using System.Text;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TrackerRealm.Jazz.Client;
using PostSharp.Extensibility;
using TrackerRealm.Jazz.Client.Custom;

namespace JazzClientTest
{
    /// <summary>
    /// A test suite that demonstrates creating and using 'ReadOnly' workflows.
    /// All 'Empty' objects are automatically read only.
    /// </summary>
    [TestClass]
    public class ReadonlyTests
    {
        #region ReadOnly
        /// <summary>
        /// This demonstrates how ReadOnly works.
        /// </summary>
        [TestMethod]
        public void ReadOnly()
        {
            using (ClientNexus nexus = ClientNexus.Create(NexusConfig.DefaultVerbose()))
            {
                MyData myData = new MyData();
                nexus.Bind(myData);
                myData.Color = "green";
                myData.Size = "small";
                myData.Item = "shirt";
                //
                // 
                myData.MakeReadOnly();

                // attempt to set a property
                #region attempt to set a property
                bool isExceptionOccurred = false;
                try
                {
                    myData.Color = "blue";
                }
                catch (Exception ex)
                {
                    Assert.IsTrue(ex is AccessViolationException);
                    isExceptionOccurred = true;
                }
                Assert.IsTrue(isExceptionOccurred);
                Assert.AreEqual("green", myData.Color);
                #endregion
                //
                // Try to make the object read write again
                //
                #region Attempt: To Make Read/Write
                isExceptionOccurred = false;
                try
                {
                    myData.MakeReadWrite();
                }
                catch (Exception ex)
                {
                    Assert.IsTrue(ex is AccessViolationException);
                    isExceptionOccurred = true;
                }
                Assert.IsTrue(isExceptionOccurred);
                Assert.IsTrue(myData.IsReadOnly);
                #endregion
                //
                // Try to make the object read write via
                // the BackDoor
                //
                #region Attempt to use back door
                isExceptionOccurred = false;
                string s = "failed to make read/write";
                try
                {
                    s = myData.BackDoor;
                }
                catch (Exception ex)
                {
                    Assert.IsTrue(ex is AccessViolationException);
                    isExceptionOccurred = true;
                }
                Assert.IsTrue(isExceptionOccurred);
                Assert.IsTrue(myData.IsReadOnly);
                Assert.AreEqual("failed to make read/write", s);
                #endregion

            }
        }
        #endregion
        #region ReadOnly_EmptyWorkflow
        /// <summary>
        /// This demonstrates that an Empty workflow is automatically 
        /// created as 'ReadOnly'.
        /// </summary>
        [TestMethod]
        public void ReadOnly_EmptyWorkflow()
        {
            using (ClientNexus nexus = ClientNexus.Create(NexusConfig.DefaultVerbose()))
            {
                MyData myData = new MyData();
                nexus.Bind(myData);
                //
                // The 'empty' object was automatically created when 
                // myData was bound to the nexus.
                MyData empty = (MyData)myData.Class.EmptyInstance;
                Assert.IsTrue(empty.IsEmpty);
                Assert.IsTrue(empty.IsReadOnly);

                // attempt to set a 'empty' property
                bool isExceptionOccurred = false;
                try
                {
                    empty.Color = "green";
                }
                catch (Exception ex)
                {
                    Assert.IsTrue(ex is AccessViolationException);
                    isExceptionOccurred = true;
                }
                Assert.IsTrue(isExceptionOccurred);
                Assert.AreEqual("", empty.Color);

            }
        }
        #endregion
        #region MyData Class - Used in all tests
        /// <summary>
        /// This is a small class that demonstrates the use the
        /// 'ReadOnly' attribute of a workflow.
        /// <para>Once a instance of a workflow has been readonly it is really
        /// difficult to make it read/write again.</para>
        /// <para>Note: That the workflow ACL mechanism may be a better fit, especially
        /// if the application requires access permission based on users.</para>
        /// </summary>
        [Jazz]
        public class MyData : jObject
        {
            #region Constructor
            /// <summary>
            /// Constructor
            /// </summary>
            public MyData()
            {
                this.Color = "";
                this.Size = "";
            }
            #endregion
            #region MakeReadOnly
            /// <summary>
            /// Once the instance is Read Only
            /// there is no way externally to make
            /// it read/write again.
            /// </summary>
            public void MakeReadOnly()
            {
                this.IsReadOnly = true;
            }
            #endregion
            #region MakeReadWrite
            /// <summary>
            /// After "IsReadOnly" is true this method is
            /// not executable.
            /// </summary>
            public void MakeReadWrite()
            {
                this.IsReadOnly = true;
            }
            #endregion
            #region BackDoor
            /// <summary>
            /// This will not work to make this instance
            /// Read/Write after it is ReadOnly.
            /// </summary>
            public string BackDoor
            {
                get
                {
                    this.IsReadOnly = true;
                    return "Success";
                }
            }
            #endregion
            #region Properties
            public string Color
            {
                get;
                set;
            }
            public string Size
            {
                get;
                set;
            }
            public string Item
            {
                get;
                set;
            }
            #endregion
        }
        #endregion
    }
}
